﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Text;

namespace InkFx.WinControl.Utils
{
    /// <summary>
    /// 颜色处理的辅助类
    /// <para>COPYRIGHT (C) InkFx http://www.ink-fx.com  License 木兰宽松许可证（MulanPSL）</para>
    /// </summary>
    public static class ColorHelper
    {
        public static void TestColorHsvHsl()
        {
            Console.WriteLine("请输入 RGB颜色 #aarrggbb (输入 exit 退出): ");
            do
            {
                var str = Console.ReadLine();
                if (string.Equals(str, "exit", StringComparison.InvariantCultureIgnoreCase)) break;

                var color = ColorHelper.FromHexARGB(str);


                ColorHSV colorHsv = color;
                Color color2 = colorHsv;
                ColorHSV colorHsv2 = color2;
                Color color3 = colorHsv2;
                ColorHSV colorHsv3 = color3;
                if (colorHsv != colorHsv3) Console.WriteLine("HSV算法误差: " + colorHsv + " <<>> " + colorHsv3);  //将 Color 和 ColorHSV 多次来回转换, 检查数据误差


                ColorHSL colorHsl = color;
                Color color4 = colorHsl;
                ColorHSL colorHsl2 = color4;
                Color color5 = colorHsl2;
                ColorHSL colorHsl3 = color5;
                if (colorHsl != colorHsl3) Console.WriteLine("HSL算法误差: " + colorHsl + " <<>> " + colorHsl3);  //将 Color 和 ColorHSV 多次来回转换, 检查数据误差


                var str2 = string.Format("RGB: [{0}, {1}, {2}] 微软HSB: [{3}, {4}, {5}]", color.R, color.G, color.B, color.GetHue(), color.GetSaturation(), color.GetBrightness());
                Console.WriteLine(str2);
                Console.WriteLine("HSV: " + colorHsv);
                Console.WriteLine("HSL: " + colorHsl);
                Console.WriteLine();
            } while (true);
        }

        #region  颜色 与 文本 转换

        /// <summary>
        /// 将 #ffffff 0xffffff #fff #ffffffff 这类数据 转换成一个 颜色
        /// <para>#8位色标准不统一: chrome-html 的格式为 #rrggbbaa, 但是 Android、.Net 的格式为 #aarrggbb</para>
        /// </summary>
        public static Color FromHexRGBA(string hexString)
        {
            bool success;
            return FromHexRGBA(hexString, out success);
        }
        /// <summary>
        /// 将 #ffffff 0xffffff #fff #ffffffff 这类数据 转换成一个 颜色
        /// <para>#8位色标准不统一: chrome-html 的格式为 #rrggbbaa, 但是 Android、.Net 的格式为 #aarrggbb</para>
        /// </summary>
        public static Color FromHexRGBA(string hexString, out bool success)
        {
            success = false;
            try
            {
                if (hexString.Contains(",") || hexString.Contains("."))
                {
                    var array = hexString.Split(new[] { ',', '.' });
                    for (int i = 0, len = array.Length; i < len; i++)
                    {
                        var item = array[i];
                        array[i] = Tools.ToInt(item).ToString("X2");
                    }
                    hexString = string.Join("", array);
                }

                string cleanHex = hexString.Replace("#", "").Replace("0x", "");
                if (cleanHex.Length == 3) { cleanHex = "" + cleanHex[0] + cleanHex[0] + cleanHex[1] + cleanHex[1] + cleanHex[2] + cleanHex[2]; }
                if (cleanHex.Length == 6) { cleanHex = cleanHex + "FF"; }

                int argb = Int32.Parse(cleanHex, NumberStyles.HexNumber);
                Color clr = Color.FromArgb(
                    (byte)((argb & 0x000000FF)),
                    (byte)((argb & 0xFF000000) >> 24),
                    (byte)((argb & 0x00FF0000) >> 16),
                    (byte)((argb & 0x0000FF00) >> 8));
                success = true;
                return clr;
            }
            catch (Exception ex) { Tools.LogWarn2(ex, string.Format("将 RGBA='{0}' 转成 Color 发生错误", hexString)); return Color.Empty; }
        }
        /// <summary>
        /// 将一个 颜色 转换成 #ffffffff 这类数据
        /// </summary>
        public static string ToHexRGBA(Color color)
        {
            string a = (color.A == 255) ? string.Empty : color.A.ToString("X2");
            string r = color.R.ToString("X2");
            string g = color.G.ToString("X2");
            string b = color.B.ToString("X2");
            return string.Format("#{0}{1}{2}{3}", r, g, b, a);
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,255,255,255 这类数据 (如果 A==255, 则不会将 A 列入到表达式中)
        /// </summary>
        public static string ToRGBA(Color color)
        {
            if (color.A == 255) return string.Format("{0}, {1}, {2}", color.R, color.G, color.B);
            return string.Format("{0}, {1}, {2}, {3}", color.R, color.G, color.B, color.A);
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,255,255,255 这类数据
        /// </summary>
        public static string ToRGBA4(Color color)
        {
            return string.Format("{0}, {1}, {2}, {3}", color.R, color.G, color.B, color.A);
        }


        /// <summary>
        /// 将 #ffffff 0xffffff #fff #ffffffff 这类数据 转换成一个 颜色
        /// <para>#8位色标准不统一: chrome-html 的格式为 #rrggbbaa, 但是 Android、.Net 的格式为 #aarrggbb</para>
        /// </summary>
        public static Color FromHexARGB(string hexString)
        {
            bool success;
            return FromHexARGB(hexString, out success);
        }
        /// <summary>
        /// 将 #ffffff 0xffffff #fff #ffffffff 这类数据 转换成一个 颜色
        /// <para>#8位色标准不统一: chrome-html 的格式为 #rrggbbaa, 但是 Android、.Net 的格式为 #aarrggbb</para>
        /// </summary>
        public static Color FromHexARGB(string hexString, out bool success)
        {
            success = false;
            try
            {
                if (hexString.Contains(",") || hexString.Contains("."))
                {
                    var array = hexString.Split(new[] { ',', '.' });
                    for (int i = 0, len = array.Length; i < len; i++)
                    {
                        var item = array[i];
                        array[i] = Tools.ToInt(item).ToString("X2");
                    }
                    hexString = string.Join("", array);
                }

                string cleanHex = hexString.Replace("#", "").Replace("0x", "");
                if (cleanHex.Length == 3) { cleanHex = "" + cleanHex[0] + cleanHex[0] + cleanHex[1] + cleanHex[1] + cleanHex[2] + cleanHex[2]; }
                if (cleanHex.Length == 6) { cleanHex = "FF" + cleanHex; }
                if (cleanHex.Length != 8) { return Color.Empty; }

                int argb = Int32.Parse(cleanHex, NumberStyles.HexNumber);
                Color clr = Color.FromArgb(
                    (byte)((argb & 0xFF000000) >> 24),
                    (byte)((argb & 0x00FF0000) >> 16),
                    (byte)((argb & 0x0000FF00) >> 8),
                    (byte)((argb & 0x000000FF)));
                success = true;
                return clr;
            }
            catch (Exception ex) { Tools.LogWarn2(ex, string.Format("将 ARGB='{0}' 转成 Color 发生错误", hexString)); return Color.Empty; }
        }
        /// <summary>
        /// 将一个 颜色 转换成 #ffffffff 这类数据
        /// </summary>
        public static string ToHexARGB(Color color)
        {
            string a = (color.A == 255) ? string.Empty : color.A.ToString("X2");
            string r = color.R.ToString("X2");
            string g = color.G.ToString("X2");
            string b = color.B.ToString("X2");
            return string.Format("#{0}{1}{2}{3}", a, r, g, b);
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,255,255,255 这类数据 (如果 A==255, 则不会将 A 列入到表达式中)
        /// </summary>
        public static string ToARGB(Color color)
        {
            if (color.A == 255) return string.Format("{0}, {1}, {2}", color.R, color.G, color.B);
            return string.Format("{0}, {1}, {2}, {3}", color.A, color.R, color.G, color.B);
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,255,255,255 这类数据
        /// </summary>
        public static string ToARGB4(Color color)
        {
            return string.Format("{0}, {1}, {2}, {3}", color.A, color.R, color.G, color.B);
        }

        /// <summary>
        /// 将 255,360,255,255 这类数据 转换成一个 颜色
        /// </summary>
        public static ColorHSV FromAHSV(string hexString)
        {
            bool success;
            return FromAHSV(hexString, out success);
        }
        /// <summary>
        /// 将 255,360,255,255 这类数据 转换成一个 颜色
        /// </summary>
        public static ColorHSV FromAHSV(string hexString, out bool success)
        {
            success = false;
            try
            {
                if (!hexString.Contains(",") && !hexString.Contains(".")) return Color.Empty;

                var list = new List<int>();
                var array = hexString.Split(new[] { ',', '.', '|', ';' });
                if (array.Length <= 2) return Color.Empty;
                for (int i = 0, len = array.Length; i < len; i++)
                {
                    var item = array[i];
                    list.Add(Tools.ToInt(item, 0));
                }
                if (list.Count <= 3) list.Insert(0, 255);
                if (list.Count != 4) return Color.Empty;


                ColorHSV clr = ColorHSV.FromAhsv(list[0], list[1], list[2], list[3]);
                success = true;
                return clr;
            }
            catch (Exception ex) { Tools.LogWarn2(ex, string.Format("将 AHSV='{0}' 转成 ColorHSV 发生错误", hexString)); return Color.Empty; }
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,360,255,255 这类数据 (如果 A==255, 则不会将 A 列入到表达式中)
        /// </summary>
        public static string ToAHSV(ColorHSV color)
        {
            if (color.A == 255) return string.Format("{0}, {1}, {2}", color.H, color.S, color.V);
            return string.Format("{0}, {1}, {2}, {3}", color.A, color.H, color.S, color.V);
        }
        /// <summary>
        /// 将一个 颜色 转换成 255,360,255,255 这类数据
        /// </summary>
        public static string ToAHSV4(ColorHSV color)
        {
            return string.Format("{0}, {1}, {2}, {3}", color.A, color.H, color.S, color.V);
        }

        #endregion

        
        #region  颜色 叠加 算法

        /// <summary>
        /// 将多个颜色 按照参数指定的顺序 进行色彩叠加, 并返回最后的颜色
        /// <para>注意: 颜色叠加的顺序不同对最后的结果影响很大</para>
        /// </summary>
        /// <param name="colors">需要叠加的颜色</param>
        /// <returns>叠加后的颜色</returns>
        public static Color BlendColor(params Color[] colors)
        {
            if (colors == null || colors.Length <= 0) return Color.Empty;
            if (colors.Length == 1) return colors[0];

            Color color = colors[0];
            for (int i = 1, len = colors.Length; i < len; i++)
            {
                color = InnerBlendColor(color, colors[i]);
            }
            return color;
        }
        private static Color InnerBlendColor(Color c1, Color c2)
        {
            int c1a = c1.A;
            if (c1a == 0) return c2;
            int c2a = c2.A;
            if (c2a == 0) return c1;
            if (c2a == 255) return c2;

            float a1 = c1a / 255.0f;
            float a2 = c2a / 255.0f;
            float a3 = a1 + a2 - a1 * a2;

            float r1 = c1.R / 255.0f;
            float r2 = c2.R / 255.0f;
            float r3 = (r1 * a1 * (1.0f - a2) + r2 * a2) * 255 / (a1 + a2 - a1 * a2);

            float g1 = c1.G / 255.0f;
            float g2 = c2.G / 255.0f;
            float g3 = (g1 * a1 * (1.0f - a2) + g2 * a2) * 255 / (a1 + a2 - a1 * a2);

            float b1 = c1.B / 255.0f;
            float b2 = c2.B / 255.0f;
            float b3 = (b1 * a1 * (1.0f - a2) + b2 * a2) * 255 / (a1 + a2 - a1 * a2);

            return Color.FromArgb((int)(a3 * 255), (int)r3, (int)g3, (int)b3);
            //return Color.FromArgb((int)Math.Round(a3 * 255), (int)Math.Round(r3), (int)Math.Round(g3), (int)Math.Round(b3));
        }

        /// <summary>
        /// 将多个颜色 按照参数指定的顺序 进行色彩叠加, 并返回最后的颜色
        /// <para>注意: 颜色叠加的顺序不同对最后的结果影响很大</para>
        /// <para>注意: 此函数使用的 GDI+图片, 性能很慢</para>
        /// </summary>
        /// <param name="colors">需要叠加的颜色</param>
        /// <returns>叠加后的颜色</returns>
        public static Color BlendColorGDI(params Color[] colors)
        {
            using (Bitmap bitmap = new Bitmap(1, 1))
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                foreach (var color in colors)
                    using (var brush = new SolidBrush(color))
                        g.FillRectangle(brush, new Rectangle(0, 0, 1, 1));

                return bitmap.GetPixel(0, 0);
            }
        }

        #endregion


        #region  图像 颜色 算法

        /// <summary>
        /// 计算指定图像的 平均色 (此颜色可以认定为 图片的色调)
        /// </summary>
        public static Color AvgColor(Image image)
        {
            return AvgColor(image, 1.0f);
        }
        /// <summary>
        /// 计算指定图像的 平均色 (此颜色可以认定为 图片的色调)
        /// <para>take取值 0~1, 比如: 统计出的颜色有100个, take设置为 0.4, 则仅统计 前40个颜色的 平均色</para>
        /// <para>至少会统计 1个颜色</para>
        /// </summary>
        public static Color AvgColor(Image image, float take)
        {
            int width = image.Width;
            int height = image.Height;
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap)) { g.DrawImage(image, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); }

            using (ColorStat stat = new ColorStat())
            {
                #region  统计 颜色

                for (int x = 0; x < width; x++)
                    for (int y = 0; y < height; y++)
                    {
                        stat.Put(bitmap.GetPixel(x, y), 1);
                        stat.Put(bitmap.GetPixel(x, height - 1 - y), 1);
                    }

                #endregion

                var result = stat.Avg(take);
                return result;
            }
        }
        /// <summary>
        /// 猜测指定图像的 背景色
        /// </summary>
        public static Color GuessBackColor(Image image)
        {
            int width = image.Width;
            int height = image.Height;
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap)) { g.DrawImage(image, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); }

            using (ColorStat stat = new ColorStat())
            {
                #region  统计 边缘区域

                int bw = Math.Min(16, Math.Max(1, width / 8));
                int bh = Math.Min(16, Math.Max(1, height / 8));

                for (int x = 0; x < width; x++)
                    for (int y = 0; y < bh; y++)
                    {
                        stat.Put(bitmap.GetPixel(x, y), (bh - y));
                        stat.Put(bitmap.GetPixel(x, height - 1 - y), (bh - y));
                    }

                for (int y = 0; y < height; y++)
                    for (int x = 0; x < bw; x++)
                    {
                        stat.Put(bitmap.GetPixel(x, y), (bw - x));
                        stat.Put(bitmap.GetPixel(width - 1 - x, y), (bw - x));
                    }

                #endregion

                #region  大图标统计 全部颜色

                if (width * height > 128 * 128)
                {
                    for (int x = bw; x < width - bw - bw; x++)
                        for (int y = bh; y < height - bh - bh; y++)
                            stat.Put(bitmap.GetPixel(x, y), 1);
                }

                #endregion

                var result = stat.Avg(0.6f);
                return result;
            }
        }

        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 含透明的彩色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColor(Color back, Image target)
        {
            return IsolateColor(back, target, 100, 100, 100);
        }
        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 含透明的彩色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <param name="toleranceBack">剔除背景时的容差值</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColor(Color back, Image target, int toleranceBack)
        {
            return IsolateColor(back, target, toleranceBack, 100, 100);
        }
        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 含透明的彩色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <param name="toleranceBack">剔除背景时的容差值</param>
        /// <param name="toleranceGray">修正边缘半透明灰色的容差值</param>
        /// <param name="toleranceColor">修正边缘半透明颜色的容差值</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColor(Color back, Image target, int toleranceBack, int toleranceGray, int toleranceColor)
        {
            int width = target.Width;
            int height = target.Height;
            var bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap)) { g.DrawImage(target, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); }

            using (var bitmapFlag = IsolateColorFlag(back, bitmap, toleranceBack))
            {
                #region  最 后 执 行 图 像 转 换

                for (int y = 0; y < height; y++)
                    for (int x = 0; x < width; x++)
                    {
                        var flag = bitmapFlag[x, y];
                        if (flag == BitmapFlag.BACK) { bitmap.SetPixel(x, y, Color.Transparent); }
                        else if (flag == BitmapFlag.COLOR || flag >= BitmapFlag.COLOR1 && flag <= BitmapFlag.COLOR8)
                        {
                            var color0 = bitmap.GetPixel(x, y);
                            var color1 = IsolateColorGrey(back, color0, toleranceColor);
                            //var color2 = BlendColor(color1, color0);
                            var color2 = Color.FromArgb((color1.A + color0.A) / 2, (color1.R + color0.R) / 2, (color1.G + color0.G) / 2, (color1.B + color0.B) / 2);

                            float rate = 1.0f;
                            if (flag == BitmapFlag.COLOR) { rate = 1.0f; }
                            else if (flag == BitmapFlag.COLOR8) { rate = 114 / 255.0f; }  //242-8*8*2
                            else if (flag == BitmapFlag.COLOR7) { rate = 144 / 255.0f; }  //242-7*7*2
                            else if (flag == BitmapFlag.COLOR6) { rate = 170 / 255.0f; }  //242-6*6*2
                            else if (flag == BitmapFlag.COLOR5) { rate = 192 / 255.0f; }  //242-5*5*2
                            else if (flag == BitmapFlag.COLOR4) { rate = 210 / 255.0f; }  //242-4*4*2
                            else if (flag == BitmapFlag.COLOR3) { rate = 224 / 255.0f; }  //242-3*3*2
                            else if (flag == BitmapFlag.COLOR2) { rate = 234 / 255.0f; }  //242-2*2*2
                            else if (flag == BitmapFlag.COLOR1) { rate = 240 / 255.0f; }  //242-1*1*2
                            var color3 = Color.FromArgb((int)(color2.A * rate), color2.R, color2.G, color2.B);
                            bitmap.SetPixel(x, y, color3);
                        }
                        else if (flag == BitmapFlag.NONE || flag >= BitmapFlag.GRAY1 && flag <= BitmapFlag.GRAY8)
                        {
                            float rate = 1.0f;
                            if (flag == BitmapFlag.NONE) { rate = 1.0f; }
                            else if (flag == BitmapFlag.GRAY1) { rate = 51 / 255.0f; }  //48+1*1*3
                            else if (flag == BitmapFlag.GRAY2) { rate = 60 / 255.0f; }  //48+2*2*3
                            else if (flag == BitmapFlag.GRAY3) { rate = 75 / 255.0f; }  //48+3*3*3
                            else if (flag == BitmapFlag.GRAY4) { rate = 96 / 255.0f; }  //48+4*4*3
                            else if (flag == BitmapFlag.GRAY5) { rate = 123 / 255.0f; } //48+5*5*3
                            else if (flag == BitmapFlag.GRAY6) { rate = 156 / 255.0f; } //48+6*6*3
                            else if (flag == BitmapFlag.GRAY7) { rate = 195 / 255.0f; } //48+7*7*3
                            else if (flag == BitmapFlag.GRAY8) { rate = 240 / 255.0f; } //48+8*8*3

                            var color0 = bitmap.GetPixel(x, y);
                            var color1 = IsolateColorGrey(back, color0, toleranceGray);
                            color1 = Color.FromArgb((int)(color1.A * rate), color1.R, color1.G, color1.B);
                            bitmap.SetPixel(x, y, color1);
                        }
                    }

                #endregion
            }

            return bitmap;
        }

        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 源图片标记对象, 此标记对象 将会反应 背景剔除过程中的 各个像素的状态
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <returns>可能的 源图片</returns>
        public static BitmapFlag IsolateColorFlag(Color back, Image target)
        {
            return IsolateColorFlag(back, target, 100);
        }
        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 源图片标记对象, 此标记对象 将会反应 背景剔除过程中的 各个像素的状态
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <param name="toleranceBack">剔除背景时的容差值</param>
        /// <returns>可能的 源图片</returns>
        public static BitmapFlag IsolateColorFlag(Color back, Image target, int toleranceBack)
        {
            int width = target.Width;
            int height = target.Height;
            using (var bitmap = new Bitmap(width, height))
            {
                using (Graphics g = Graphics.FromImage(bitmap)) { g.DrawImage(target, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); }
                var bitmapFlag = IsolateColorFlag(back, bitmap, toleranceBack);
                return bitmapFlag;
            }
        }
        private static BitmapFlag IsolateColorFlag(Color back, Bitmap bitmap, int toleranceBack)
        {
            int width = bitmap.Width;
            int height = bitmap.Height;
            BitmapFlag bitmapFlag = new BitmapFlag(width, height);

            #region  定 位 背 景 区 域

            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    var color0 = bitmap.GetPixel(x, y);
                    var diff = Diff(color0, back);
                    if (diff <= toleranceBack) { bitmapFlag[x, y] = BitmapFlag.NONE; }
                    else { bitmapFlag[x, y] = BitmapFlag.COLOR; }
                }

            #endregion

            #region  再 定 位 边 缘 区 域

            bitmapFlag.ResetRegion();

            #endregion

            return bitmapFlag;
        }



        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 透明较高的彩色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <param name="toleranceGray">修正半透明灰色的容差值</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColorAlpha(Color back, Image target)
        {
            return IsolateColorGray(back, target, 100);
        }
        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 含透明的灰色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColorGray(Color back, Image target)
        {
            return IsolateColorGray(back, target, 442);
        }
        /// <summary>
        /// 将 目标图片 中的 背景色 剔除, 并返回一个 可能的 含透明的灰色源图片, 此源图片+背景色≈目标图片
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的图片 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的图片</param>
        /// <param name="toleranceGray">修正半透明灰色的容差值</param>
        /// <returns>可能的 源图片</returns>
        public static Bitmap IsolateColorGray(Color back, Image target, int toleranceGray)
        {
            int width = target.Width;
            int height = target.Height;
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap)) { g.DrawImage(target, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); }

            #region  最 后 执 行 图 像 转 换

            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    var color0 = bitmap.GetPixel(x, y);
                    var color1 = IsolateColorGrey(back, color0, toleranceGray);
                    //color1 = Color.FromArgb(color1.A, color1.R, color1.G, color1.B);
                    bitmap.SetPixel(x, y, color1);
                }

            #endregion

            return bitmap;
        }





        /// <summary>
        /// 将 目标色 中的 背景色 剔除, 并返回一个 可能的 含透明的彩色颜色, 此颜色+背景色≈目标色
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的颜色 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的颜色</param>
        /// <param name="tolerance">如果推断的 源色 在重新混合后 与 目标色 差距过大, 则认定 源色就是目标色 (tolerance 就是这个 '差距')</param>
        /// <returns>可能的 源色</returns>
        public static Color IsolateColor(Color back, Color target, int tolerance)
        {
            if (back.A > target.A) back = Color.FromArgb(target.A, back.R, back.G, back.B);
            if (target.A == back.A && target.R == back.R && target.G == back.G && target.B == back.B) return Color.Empty;

            //ColorHSV back2 = back;
            //ColorHSV target2 = target;
            //if (Math.Abs(back2.H - target2.H) % 180 >= 60) return target;  //如果 目标色 和 背景色 在色相上相差太大, 则认定 目标色即源色
            //var diff = DiffColor(back, target);
            //if (diff > 150) return target;

            int resultA = int.MaxValue;
            float resultDiff = float.MaxValue;
            Color result = target;

            int[] steps = new int[] { /*85,*/ 51, 17, 5, 3, 1 };
            int amin = 0, rmin = 0, gmin = 0, bmin = 0;
            int amax = 200, rmax = 255, gmax = 255, bmax = 255;

            for (int i = 0, len = steps.Length; i < len; i++)
            {
                int step = steps[i];
                int half = step / 2;

                for (int a = amin; a <= amax; a = a + step)
                    for (int r = rmin; r <= rmax; r = r + step)
                        for (int g = gmin; g <= gmax; g = g + step)
                            for (int b = bmin; b <= bmax; b = b + step)
                            {
                                Color color = Color.FromArgb(a, r, g, b);
                                Color blend = BlendColor(back, color);
                                var diff2 = Diff(blend, target);
                                if (diff2 < resultDiff) { resultDiff = diff2; resultA = a; result = color; }
                                if (diff2 == resultDiff && resultA > a) { resultDiff = diff2; resultA = a; result = color; }
                            }

                amin = Math.Max(amin, result.A - half);
                rmin = Math.Max(rmin, result.R - half);
                gmin = Math.Max(gmin, result.G - half);
                bmin = Math.Max(bmin, result.B - half);
                amax = Math.Min(amax, result.A + half);
                rmax = Math.Min(rmax, result.R + half);
                gmax = Math.Min(gmax, result.G + half);
                bmax = Math.Min(bmax, result.B + half);
            }

            var diff = Diff(BlendColor(back, result), target);
            if (diff >= tolerance) return target;
            //Console.WriteLine(diff);
            return result;
        }
        /// <summary>
        /// 将 目标色 中的 背景色 剔除, 并返回一个 可能的 含透明的灰色颜色, 此颜色+背景色≈目标色
        /// <para>混合算法: 背景色+源色=目标色</para>
        /// <para>本分离算法: 已知 背景色、目标色, 求取可能的 源色</para>
        /// <para>注意: 颜色混合算法理论上本不可逆, 本分离算法返回的颜色 只是一个可能值</para>
        /// </summary>
        /// <param name="back">需要剔除的背景色</param>
        /// <param name="target">与背景色混合后的颜色</param>
        /// <param name="tolerance">如果推断的 源色 在重新混合后 与 目标色 差距过大, 则认定 源色就是目标色 (tolerance 就是这个 '差距')</param>
        /// <returns>可能的 源色</returns>
        public static Color IsolateColorGrey(Color back, Color target, int tolerance)
        {
            if (back.A > target.A) back = Color.FromArgb(target.A, back.R, back.G, back.B);
            if (target.A == back.A && target.R == back.R && target.G == back.G && target.B == back.B) return Color.Empty;

            //ColorHSV back2 = back;
            //ColorHSV target2 = target;
            //if (Math.Abs(back2.H - target2.H) % 180 >= 60) return target;  //如果 目标色 和 背景色 在色相上相差太大, 则认定 目标色即源色
            //var diff = DiffColor(back, target);
            //if (diff > 150) return target;

            int resultA = int.MaxValue;
            float resultDiff = float.MaxValue;
            Color result = target;

            int[] steps = new int[] { /*85,*/ 51, 17, 5, 3, 1 }; //这几个数 都能被 255 整除
            int amin = 0, vmin = 0;
            int amax = 200, vmax = 255;

            for (int i = 0, len = steps.Length; i < len; i++)
            {
                int step = steps[i];
                int half = step / 2;

                for (int a = amin; a <= amax; a = a + step)
                    for (int v = vmin; v <= vmax; v = v + step)
                    {
                        Color color = Color.FromArgb(a, v, v, v);
                        Color blend = BlendColor(back, color);
                        var diff2 = Diff(blend, target);
                        if (diff2 < resultDiff) { resultDiff = diff2; resultA = a; result = color; }
                        if (diff2 == resultDiff && resultA > a) { resultDiff = diff2; resultA = a; result = color; }
                    }

                amin = Math.Max(amin, result.A - half);
                vmin = Math.Max(vmin, result.R - half);
                amax = Math.Min(amax, result.A + half);
                vmax = Math.Min(vmax, result.R + half);
            }

            var diff = Diff(BlendColor(back, result), target);
            if (diff >= tolerance) return Color.FromArgb(result.A, target.R, target.G, target.B);
            //Console.WriteLine(diff);
            return result;
        }

        #endregion


        #region  其他颜色函数

        /// <summary>
        /// 计算两个颜色的 差距, 返回值为 0~442, 值越大表示 颜色差别越大
        /// </summary>
        public static float Diff(Color color1, Color color2)
        {
            //三维坐标系中, 两点距离公式(高中数学): d=√[(x1-x2)^2+(y1-y2)^2+(z1-z2)^2]
            //return (float)Math.Sqrt((color1.A - color2.A) * (color1.A - color2.A) + (color1.R - color2.R) * (color1.R - color2.R) + (color1.G - color2.G) * (color1.G - color2.G) + (color1.B - color2.B) * (color1.B - color2.B));


            //下面的算法 是作者的个人臆想的算法, 可能不符合色彩科学, 可能不准确:  
            //  RGB 用于计算 三维做标记中的 两点距离
            //  A 用于确定 系数:
            //    如果两个颜色 都是 255 透明度, 则直接使用 三维距离作为差值
            //    如果两个颜色 都是 0   透明度, 则差值为 0 (比如: 全透明的红色 和 全透明的蓝色 认定为无差距)
            var diff = (float)Math.Sqrt((color1.R - color2.R) * (color1.R - color2.R) + (color1.G - color2.G) * (color1.G - color2.G) + (color1.B - color2.B) * (color1.B - color2.B));
            var rate = (float)(color1.A + color2.A) / 510.0F;
            return (int)(diff * rate);
        }

        /// <summary>
        /// 获取指定颜色的 淡颜色
        /// </summary>
        public static Color Light(Color color)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.Light(color);
            return DarkLightColor(color, 0.25f);
        }
        /// <summary>
        /// 获取指定颜色的 更淡颜色
        /// </summary>
        public static Color LightLight(Color color)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.LightLight(color);
            return DarkLightColor(color, 0.5f);
        }
        /// <summary>
        /// 获取指定颜色的 深颜色
        /// </summary>
        public static Color Dark(Color color)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.Dark(color);
            return DarkLightColor(color, -0.25f);
        }
        /// <summary>
        /// 获取指定颜色的 更深颜色
        /// </summary>
        public static Color DarkDark(Color color)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.DarkDark(color);
            return DarkLightColor(color, -0.5f);
        }
        /// <summary>
        /// 获取指定颜色的 变淡指定系数颜色 (参数 ratio 取值范围: 0~1)
        /// </summary>
        public static Color Light(Color color, float ratio)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.Light(color, percOfLightLight);
            return DarkLightColor(color, ratio);
        }
        /// <summary>
        /// 获取指定颜色的 变深指定系数颜色 (参数 ratio 取值范围: 0~1)
        /// </summary>
        public static Color Dark(Color color, float ratio)
        {
            if (color.A <= 0 || color.IsEmpty) return Color.Transparent;
            //return System.Windows.Forms.ControlPaint.Dark(color, percOfDarkDark);
            return DarkLightColor(color, 0 - ratio);
        }
        /// <summary>
        /// 获取指定颜色的 变淡深指定系数颜色 (参数 ratio 取值范围: -1~1)
        /// </summary>
        public static Color DarkLightColor(Color color, float ratio)
        {
            if (Math.Abs(ratio - 0) < 0.0000001) return color;

            float r = color.R;
            float g = color.G;
            float b = color.B;

            if (ratio > 0)
            {
                r = r + (255 - r) * ratio;
                g = g + (255 - g) * ratio;
                b = b + (255 - b) * ratio;
            }
            else
            {
                r = r + r * ratio;
                g = g + g * ratio;
                b = b + b * ratio;
            }

            r = Math.Min(255, Math.Max(0, r));
            g = Math.Min(255, Math.Max(0, g));
            b = Math.Min(255, Math.Max(0, b));
            return Color.FromArgb(color.A, (int)r, (int)g, (int)b);
        }



        #endregion

    }


    #region  临时颜色对象

    /// <summary>
    /// 标记位图的临时对象
    /// </summary>
    public class BitmapFlag : IDisposable
    {
        public BitmapFlag(int width, int height)
        {
            m_Width = width;
            m_Height = height;
            m_Flags = new byte[m_Width * m_Height];
        }

        public const byte NONE = 0;
        public const byte BACK = 254;
        public const byte COLOR = 255;
        public const byte TRANSPARENT = 1;
        public const byte GRAY1 = 101;
        public const byte GRAY2 = 102;
        public const byte GRAY3 = 103;
        public const byte GRAY4 = 104;
        public const byte GRAY5 = 105;
        public const byte GRAY6 = 106;
        public const byte GRAY7 = 107;
        public const byte GRAY8 = 108;

        public const byte COLOR1 = 201;
        public const byte COLOR2 = 202;
        public const byte COLOR3 = 203;
        public const byte COLOR4 = 204;
        public const byte COLOR5 = 205;
        public const byte COLOR6 = 206;
        public const byte COLOR7 = 207;
        public const byte COLOR8 = 208;


        private int m_Width = 0;
        private int m_Height = 0;
        private byte[] m_Flags = null;

        public byte this[int x, int y]
        {
            get
            {
                long index = y * m_Width + x;
                return m_Flags[index];
            }
            set
            {
                long index = y * m_Width + x;
                m_Flags[index] = value;
            }
        }
        public Bitmap ToBitmap()
        {
            Bitmap bitmap = new Bitmap(m_Width, m_Height);
            for (int y = 0; y < m_Height; y++)
                for (int x = 0; x < m_Width; x++)
                {
                    var flag = this[x, y];
                    if (flag == BACK) { bitmap.SetPixel(x, y, Color.LightBlue); }
                    else if (flag == COLOR) { bitmap.SetPixel(x, y, Color.Red); }
                    else if (flag == TRANSPARENT) { bitmap.SetPixel(x, y, Color.Transparent); }

                    else if (flag == GRAY1) { bitmap.SetPixel(x, y, Color.FromArgb(51, Color.Gray)); }  //48+1*1*3
                    else if (flag == GRAY2) { bitmap.SetPixel(x, y, Color.FromArgb(60, Color.Gray)); }  //48+2*2*3
                    else if (flag == GRAY3) { bitmap.SetPixel(x, y, Color.FromArgb(75, Color.Gray)); }  //48+3*3*3
                    else if (flag == GRAY4) { bitmap.SetPixel(x, y, Color.FromArgb(96, Color.Gray)); }  //48+4*4*3
                    else if (flag == GRAY5) { bitmap.SetPixel(x, y, Color.FromArgb(123, Color.Gray)); } //48+5*5*3
                    else if (flag == GRAY6) { bitmap.SetPixel(x, y, Color.FromArgb(156, Color.Gray)); } //48+6*6*3
                    else if (flag == GRAY7) { bitmap.SetPixel(x, y, Color.FromArgb(195, Color.Gray)); } //48+7*7*3
                    else if (flag == GRAY8) { bitmap.SetPixel(x, y, Color.FromArgb(240, Color.Gray)); } //48+8*8*3

                    else if (flag == COLOR8) { bitmap.SetPixel(x, y, Color.FromArgb(114, Color.Red)); }  //242-8*8*2
                    else if (flag == COLOR7) { bitmap.SetPixel(x, y, Color.FromArgb(144, Color.Red)); }  //242-7*7*2
                    else if (flag == COLOR6) { bitmap.SetPixel(x, y, Color.FromArgb(170, Color.Red)); }  //242-6*6*2
                    else if (flag == COLOR5) { bitmap.SetPixel(x, y, Color.FromArgb(192, Color.Red)); }  //242-5*5*2
                    else if (flag == COLOR4) { bitmap.SetPixel(x, y, Color.FromArgb(210, Color.Red)); }  //242-4*4*2
                    else if (flag == COLOR3) { bitmap.SetPixel(x, y, Color.FromArgb(224, Color.Red)); }  //242-3*3*2
                    else if (flag == COLOR2) { bitmap.SetPixel(x, y, Color.FromArgb(234, Color.Red)); }  //242-2*2*2
                    else if (flag == COLOR1) { bitmap.SetPixel(x, y, Color.FromArgb(240, Color.Red)); }  //242-1*1*2 
                }
            return bitmap;
        }
        public void ResetRegion()
        {
            //执行 BACK 点的感染
            for (int x = 0; x < m_Width; x++) { if (this[x, 0] == NONE) { Infect(x, 0, BACK); } if (this[x, m_Height - 1] == NONE) { Infect(x, m_Height - 1, BACK); } }
            for (int y = 0; y < m_Height; y++) { if (this[0, y] == NONE) { Infect(0, y, BACK); } if (this[m_Width - 1, y] == NONE) { Infect(m_Width - 1, y, BACK); } }

            //查找外围边缘
            for (int y = 0; y < m_Height; y++)
                for (int x = 0; x < m_Width; x++)
                {
                    var flag1 = this[x, y];
                    if (flag1 != BACK && flag1 != NONE) { continue; }

                    int gray = 0;
                    if (x - 1 >= 0) { if (this[x - 1, y] == COLOR) { gray = gray + 2; } }
                    if (x + 1 < m_Width) { if (this[x + 1, y] == COLOR) { gray = gray + 2; } }
                    if (y - 1 >= 0) { if (this[x, y - 1] == COLOR) { gray = gray + 2; } }
                    if (y + 1 < m_Height) { if (this[x, y + 1] == COLOR) { gray = gray + 2; } }

                    if (x - 1 >= 0 && y - 1 >= 0) { if (this[x - 1, y - 1] == COLOR) { gray = gray + 1; } }
                    if (x + 1 < m_Width && y - 1 >= 0) { if (this[x + 1, y - 1] == COLOR) { gray = gray + 1; } }
                    if (x - 1 >= 0 && y + 1 < m_Height) { if (this[x - 1, y + 1] == COLOR) { gray = gray + 1; } }
                    if (x + 1 < m_Width && y + 1 < m_Height) { if (this[x + 1, y + 1] == COLOR) { gray = gray + 1; } }

                    if (gray == 1) this[x, y] = GRAY1;
                    else if (gray == 2) this[x, y] = GRAY2;
                    else if (gray == 3) this[x, y] = GRAY3;
                    else if (gray == 4) this[x, y] = GRAY4;
                    else if (gray == 5) this[x, y] = GRAY5;
                    else if (gray == 6) this[x, y] = GRAY6;
                    else if (gray == 7) this[x, y] = GRAY7;
                    else if (gray >= 8) this[x, y] = GRAY8;
                }

            //查找内部边缘
            for (int y = 0; y < m_Height; y++)
                for (int x = 0; x < m_Width; x++)
                {
                    var flag1 = this[x, y];
                    if (flag1 != COLOR) { continue; }

                    int color = 0;
                    if (x - 1 >= 0) { var flag = this[x - 1, y]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 2; } }
                    if (x + 1 < m_Width) { var flag = this[x + 1, y]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 2; } }
                    if (y - 1 >= 0) { var flag = this[x, y - 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 2; } }
                    if (y + 1 < m_Height) { var flag = this[x, y + 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 2; } }

                    if (x - 1 >= 0 && y - 1 >= 0) { var flag = this[x - 1, y - 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 1; } }
                    if (x + 1 < m_Width && y - 1 >= 0) { var flag = this[x + 1, y - 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 1; } }
                    if (x - 1 >= 0 && y + 1 < m_Height) { var flag = this[x - 1, y + 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 1; } }
                    if (x + 1 < m_Width && y + 1 < m_Height) { var flag = this[x + 1, y + 1]; if (flag >= GRAY1 && flag <= GRAY2) { color = color + 1; } }

                    if (color == 1) this[x, y] = COLOR1;
                    else if (color == 2) this[x, y] = COLOR2;
                    else if (color == 3) this[x, y] = COLOR3;
                    else if (color == 4) this[x, y] = COLOR4;
                    else if (color == 5) this[x, y] = COLOR5;
                    else if (color == 6) this[x, y] = COLOR6;
                    else if (color == 7) this[x, y] = COLOR7;
                    else if (color >= 8) this[x, y] = COLOR8;
                }
        }
        /// <summary>
        /// 将指定的 x, y 点 标记为指定的 Flag值, 并对 四周的 NONE 点 进行扩散感染
        /// </summary>
        public void Infect(int x, int y, byte flag)
        {
            //注意: 此感染算法 不能使用 递归 (否则 像素太多时, 将导致 堆栈溢出)
            //将指定的 Flag 周围的 NONE 感染为 Flag, 新感染的 Flag 继续执行感染

            this[x, y] = flag;

            int count = 0;
            List<Point> listNew = new List<Point> { new Point(x, y) };

            do
            {
                int index = count;
                count = listNew.Count;
                for (int i = index, len = count; i < len; i++) //只对新点 进行感染操作
                {
                    var pt = listNew[i];
                    int x2 = pt.X, y2 = pt.Y;
                    if (x2 - 1 >= 0) { if (this[x2 - 1, y2] == NONE) { this[x2 - 1, y2] = flag; listNew.Add(new Point(x2 - 1, y2)); } }
                    if (x2 + 1 < m_Width) { if (this[x2 + 1, y2] == NONE) { this[x2 + 1, y2] = flag; listNew.Add(new Point(x2 + 1, y2)); } }
                    if (y2 - 1 >= 0) { if (this[x2, y2 - 1] == NONE) { this[x2, y2 - 1] = flag; listNew.Add(new Point(x2, y2 - 1)); } }
                    if (y2 + 1 < m_Height) { if (this[x2, y2 + 1] == NONE) { this[x2, y2 + 1] = flag; listNew.Add(new Point(x2, y2 + 1)); } }
                }
            } while (listNew.Count > count);



            #region  作废的代码

            //do
            //{
            //    count = listNew.Count;

            //    for (int t = x - 1; t >= 0; t--)
            //    {
            //        if (this[t, y] == NONE)
            //        {
            //            this[t, y] = flag;
            //            listNew.Add(new Point(t, y));
            //        }
            //        else { break; }
            //    }
            //    for (int t = x + 1; t < m_Width; t++)
            //    {
            //        if (this[t, y] == NONE)
            //        {
            //            this[t, y] = flag;
            //            listNew.Add(new Point(t, y));
            //        }
            //        else { break; }
            //    }

            //    for (int t = y - 1; t >= 0; t--)
            //    {
            //        if (this[x, t] == NONE)
            //        {
            //            this[x, t] = flag;
            //            listNew.Add(new Point(x, t));
            //        }
            //        else { break; }
            //    }

            //    for (int t = y + 1; t < m_Height; t++)
            //    {
            //        if (this[x, t] == NONE)
            //        {
            //            this[x, t] = flag;
            //            listNew.Add(new Point(x, t));
            //        }
            //        else { break; }
            //    }

            //} while (listNew.Count > count);

            #endregion
        }
        public override string ToString()
        {
            return m_Width + "x" + m_Height;
        }
        public void Dispose()
        {
            m_Flags = null;
        }

    }

    /// <summary>
    /// 对颜色采点进行统计
    /// </summary>
    public class ColorStat : IDisposable
    {
        private Hash<Color, ulong> m_HashColor;

        public int Count
        {
            get { return m_HashColor == null ? 0 : m_HashColor.Count; }
        }
        /// <summary>
        /// 将一个颜色加入数目统计
        /// </summary>
        public void Put(Color color)
        {
            Put(color, 1);
        }
        /// <summary>
        /// 将一个颜色加入数目统计
        /// </summary>
        public void Put(Color color, int rate)
        {
            if (m_HashColor == null) m_HashColor = new Hash<Color, ulong>();
            var temp = Color.FromArgb(color.A, color.R, color.G, color.B);
            ulong count = m_HashColor[temp];
            m_HashColor[temp] = count + 1;
        }
        /// <summary>
        /// 返回 统计次数最多的颜色
        /// </summary>
        public Color Max()
        {
            var hash = Stat(1);
            if (hash == null || hash.Count <= 0) return Color.Empty;
            foreach (var pair in hash) return pair.Key;
            return Color.Empty;
        }
        /// <summary>
        /// 返回 所有颜色的平均色
        /// </summary>
        public Color Avg()
        {
            return Avg(1);
        }
        /// <summary>
        /// 返回 色彩做多的一组颜色的平均色
        /// <para>take取值 0~1, 比如: 统计出的颜色有100个, take设置为 0.4, 则仅统计 前40个颜色的 平均色</para>
        /// <para>至少会统计 1个颜色</para>
        /// </summary>
        public Color Avg(float take)
        {
            var count = Math.Max(1, (int)Math.Round(this.Count * take));
            var hash = Stat(count);
            if (hash == null || hash.Count <= 0) return Color.Empty;

            double c = 0;
            double sa = 0, sr = 0, sg = 0, sb = 0;
            foreach (var pair in hash)
            {
                var cl = pair.Key;
                var ct = pair.Value;

                c = c + ct;
                sa = sa + cl.A * ct;
                sr = sr + cl.R * ct;
                sg = sg + cl.G * ct;
                sb = sb + cl.B * ct;
            }

            var a = Math.Min(255, (int)Math.Round(sa / c));
            var r = Math.Min(255, (int)Math.Round(sr / c));
            var g = Math.Min(255, (int)Math.Round(sg / c));
            var b = Math.Min(255, (int)Math.Round(sb / c));
            return Color.FromArgb(a, r, g, b);
        }
        /// <summary>
        /// 返回 颜色最多的 前几个颜色 
        /// <para>如果 take小于等于0, 则返回全部统计颜色</para>
        /// </summary>
        public Hash<Color, ulong> Stat(int take)
        {
            var hash = new Hash<Color, ulong>();
            if (m_HashColor == null) return hash;

            var list = new List<KeyValuePair<Color, ulong>>();
            foreach (var pair in m_HashColor) list.Add(new KeyValuePair<Color, ulong>(pair.Key, pair.Value));
            list.Sort((x, y) => { ulong vx = x.Value; ulong vy = y.Value; return (vx == vy) ? 0 : (vy > vx ? 1 : -1); });
            for (int i = 0, len = Math.Min(take, list.Count); i < len; i++) { var pair = list[i]; hash[pair.Key] = (ulong)pair.Value; }
            return hash;
        }

        public void Dispose()
        {
            if (m_HashColor != null) { m_HashColor.Clear(); m_HashColor = null; }
        }


    }


    #endregion

    #region  HSL | HSV 色彩

    //-------------------------------------------------------------------------------
    //    作者:     InkFx (514286339@qq.com)  2019-12-09 06:01
    //    开源协议: 木兰宽松许可证  2019年8月 http://license.coscl.org.cn/MulanPSL
    //
    //
    //    本段代码参考如下网址:
    //
    //    HSV
    //    https://www.cnblogs.com/nanfei/p/9489341.html
    //    https://baike.baidu.com/item/HSL/1443144?fr=aladdin
    //    https://baike.baidu.com/item/HSV/547122?fr=aladdin
    //    https://blog.csdn.net/kakiebu/article/details/79476235
    //    https://blog.csdn.net/qq_20095389/article/details/89084708
    //    https://www.jianshu.com/p/1c4c468aabe5
    //    https://www.cnblogs.com/wangyblzu/p/5710715.html
    //    https://www.cnblogs.com/JorSean/p/9412952.html
    //    https://blog.csdn.net/qq_33759946/article/details/90295377
    //    https://www.cnblogs.com/wangyblzu/p/5710715.html
    //    https://blog.csdn.net/taily_duan/article/details/51506776
    //
    //    HSL
    //    https://baike.baidu.com/item/HSL/1443144?fr=aladdin
    //
    //    其他
    //    https://blog.csdn.net/u010712012/article/details/85240100
    //    https://blog.csdn.net/jiangxinyu/article/details/8000999
    //
    //    测试网站
    //    https://www.colorhexa.com/ff0000
    //
    //-------------------------------------------------------------------------------



    /// <summary>
    /// HSL 体系下的 色彩结构
    /// </summary>
    public struct ColorHSL
    {
        public static ColorHSL FromArgb(Color color)
        {
            if (color.IsEmpty) return new ColorHSL(0, 0, 0, 0);

            int a = color.A, r = color.R, g = color.G, b = color.B;
            if (r == 255 && g == 255 && b == 255) return new ColorHSL(a, 0, 0, 255); //纯白色时, l==255 且 h s 参数是无效的(#FFFFFF 的 h s 可以是任意值)
            if (r == 0 && g == 0 && b == 0) return new ColorHSL(a, 0, 0, 0);         //纯黑色时, l==0   且 h s 参数是无效的(#000000 的 h s 可以是任意值)

            //以下代码未经过 高压测试, 可能存在BUG
            float r1 = color.R / 255f;
            float g1 = color.G / 255f;
            float b1 = color.B / 255f;
            float h = 0, s = 0, l = 0;

            float v = Math.Max(Math.Max(r1, g1), b1);
            float m = Math.Min(Math.Min(r1, g1), b1);

            l = (m + v) / 2.0f;
            if (l <= 0.0) { return new ColorHSL(a, 0, 0, 0); }

            float diff = v - m;
            s = diff;
            if (s > 0.0) { s = s / ((l <= 0.5f) ? (v + m) : (2.0f - v - m)); }
            else { return new ColorHSL(a, 0, 0, 0); }

            float r2 = (v - r1) / diff;
            float g2 = (v - g1) / diff;
            float b2 = (v - b1) / diff;
            if (r1 == v) { h = (g1 == m ? 5.0f + b2 : 1.0f - g2); }
            else if (g1 == v) { h = (b1 == m ? 1.0f + r2 : 3.0f - b2); }
            else { h = (r1 == m ? 3.0f + g2 : 5.0f - r2); }
            h = h / 6.0f;

            return new ColorHSL(a, (int)Math.Round(h * 360) % 360, (int)Math.Round(s * 255), (int)Math.Round(l * 255));
        }
        public static ColorHSL FromArgb(int alpha, Color color)
        {
            return ColorHSL.FromArgb(Color.FromArgb(alpha, color));
        }
        public static ColorHSL FromArgb(int red, int green, int blue)
        {
            return ColorHSL.FromArgb(Color.FromArgb(red, green, blue));
        }
        public static ColorHSL FromArgb(int alpha, int red, int green, int blue)
        {
            return ColorHSL.FromArgb(Color.FromArgb(alpha, red, green, blue));
        }
        public static ColorHSL FromAhsl(int hue, int saturation, int lightness)
        {
            return ColorHSL.FromAhsl((int)byte.MaxValue, hue, saturation, lightness);
        }
        public static ColorHSL FromAhsl(int alpha, int hue, int saturation, int lightness)
        {
            ColorHSL.Check256(alpha, "alpha");
            ColorHSL.Check360(hue, "hue");
            ColorHSL.Check256(saturation, "saturation");
            ColorHSL.Check256(lightness, "lightness");
            return new ColorHSL(alpha, hue, saturation, lightness);
        }
        public static bool operator ==(ColorHSL left, ColorHSL right)
        {
            if (left.m_A != right.m_A || left.m_H != right.m_H || left.m_S != right.m_S || left.m_L != right.m_L) return false;
            return true;
        }
        public static bool operator !=(ColorHSL left, ColorHSL right)
        {
            return !(left == right);
        }
        public static implicit operator ColorHSL(Color color)
        {
            return ColorHSL.FromArgb(color);
        }
        public static implicit operator Color(ColorHSL color)
        {
            return color.ToColor();
        }


        private const string m_ArgumentErrorFormat = "错误的参数 {0} 取值 {1} 不在范围 [{2}, {3}] 内";
        private static void Check256(int value, string name)
        {
            if (value >= 0 && value <= (int)byte.MaxValue) return;
            throw new ArgumentException(string.Format(m_ArgumentErrorFormat, (object)name, (object)value, (object)0, (object)(int)byte.MaxValue));
        }
        private static void Check360(int value, string name)
        {
            if (value >= 0 && value <= (int)359) return;
            throw new ArgumentException(string.Format(m_ArgumentErrorFormat, (object)name, (object)value, (object)0, (object)(int)359));
        }


        private ColorHSL(int alpha, int hue, int saturation, int lightness)
        {
            this.m_A = (ushort)alpha;
            this.m_H = (ushort)hue;
            this.m_S = (ushort)saturation;
            this.m_L = (ushort)lightness;
        }

        private readonly ushort m_A;
        private readonly ushort m_H;
        private readonly ushort m_S;
        private readonly ushort m_L;

        /// <summary>
        /// 透明度 [0, 255]
        /// </summary>
        public int A
        {
            get { return this.m_A; }
        }
        /// <summary>
        /// 色相 [0, 360]
        /// </summary>
        public int H
        {
            get { return this.m_H; }
        }
        /// <summary>
        /// 饱和度 [0, 255]
        /// </summary>
        public int S
        {
            get { return this.m_S; }
        }
        /// <summary>
        /// 亮度 [0, 255]
        /// </summary>
        public int L
        {
            get { return this.m_L; }
        }

        /// <summary>
        /// 饱和度 [0, 100]
        /// </summary>
        public int S100
        {
            get { return (int)Math.Round(((float)m_S * 100) / 255); }
        }
        /// <summary>
        /// 亮度 [0, 100]
        /// </summary>
        public int L100
        {
            get { return (int)Math.Round(((float)m_L * 100) / 255); }
        }


        public Color ToColor()
        {
            int a = this.m_A, l0 = this.m_L;
            if (l0 == 255) return Color.FromArgb(a, 255, 255, 255);                     //纯白色时, l==255 且 h s 参数是无效的(#FFFFFF 的 h s 可以是任意值)
            if (l0 == 0) return Color.FromArgb(a, 0, 0, 0);                             //纯黑色时, l==0   且 h s 参数是无效的(#000000 的 h s 可以是任意值)


            //以下代码未经过 高压测试, 可能存在BUG
            float h = this.m_H / 360.0f, s = this.m_S / 255.0f, l = this.m_L / 255.0f;
            float r = l, g = l, b = l;
            float v = (l <= 0.5f) ? (l * (1.0f + s)) : (l + s - l * s);

            if (v > 0)
            {
                float m = l + l - v;
                float sv = (v - m) / v;
                h = h * 6.0f;
                int hi = (int)h;
                float hhi = h - hi;
                float vsf = v * sv * hhi;
                float mvsf = m + vsf;
                float vvsf = v - vsf;

                switch (hi)
                {
                    case 0: { r = v; g = mvsf; b = m; break; }                       
                    case 1: { r = vvsf; g = v; b = m; break; }
                    case 2: { r = m; g = v; b = mvsf; break; }
                    case 3: { r = m; g = vvsf; b = v; break; }
                    case 4: { r = mvsf; g = m; b = v; break; }
                    case 5: { r = v; g = m; b = vvsf; break; }
                }
            }

            return Color.FromArgb(a, (int)Math.Round(r * 255.0f), (int)Math.Round(g * 255.0f), (int)Math.Round(b * 255.0f));
        }
        public override string ToString()
        {
            var color = ToColor();
            return color + string.Format(" [H={0}, S={1}, L={2}, S100={3}, L100={4}]", this.H, this.S, this.L, this.S100, this.L100);
        }
        public override bool Equals(object obj)
        {
            if (obj is ColorHSL) { return (ColorHSL)obj == this; }
            return false;
        }
        public override int GetHashCode()
        {
            return this.m_A.GetHashCode() ^ this.m_H.GetHashCode() ^ this.m_S.GetHashCode() ^ this.m_L.GetHashCode();
        }
    }

    /// <summary>
    /// HSV 体系下的 色彩结构
    /// </summary>
    public struct ColorHSV
    {
        public static ColorHSV FromArgb(Color color)
        {
            if (color.IsEmpty) return new ColorHSV(0, 0, 0, 0);

            int a = color.A, r = color.R, g = color.G, b = color.B;
            if (r == 255 && g == 255 && b == 255) return new ColorHSV(a, 0, 0, 255); //纯白色时, s==0 且 v==255  而  h 参数是无效的(#FFFFFF 的h 可以是任意值)
            if (r == 0 && g == 0 && b == 0) return new ColorHSV(a, 0, 0, 0);         //纯黑色时, v==0 且         而  h s 参数是无效的(#000000 的 h s 可以是任意值)

            //以下代码未经过 高压测试, 可能存在BUG
            float h = 0, s = 0, v = 0;
            float min = Math.Min(r, Math.Min(g, b));
            float max = Math.Max(r, Math.Max(g, b));
            float diff = max - min;
            v = max;
            s = max != 0 ? (255 * diff / max) : 0;
            if (s != 0)
            {
                if (r == max) { h = (g - b) / diff; }
                else { if (g == max) { h = 2 + (b - r) / diff; } else { h = 4 + (r - g) / diff; } }
            }
            else { h = -1; }

            h = h * 60;
            if (h < 0) { h = h + 360; }
            return new ColorHSV(color.A, (int)Math.Round(h) % 360, (int)Math.Round(s), (int)Math.Round(v));
        }
        public static ColorHSV FromArgb(int alpha, Color color)
        {
            return ColorHSV.FromArgb(Color.FromArgb(alpha, color));
        }
        public static ColorHSV FromArgb(int red, int green, int blue)
        {
            return ColorHSV.FromArgb(Color.FromArgb(red, green, blue));
        }
        public static ColorHSV FromArgb(int alpha, int red, int green, int blue)
        {
            return ColorHSV.FromArgb(Color.FromArgb(alpha, red, green, blue));
        }
        public static ColorHSV FromAhsv(int hue, int saturation, int value)
        {
            return ColorHSV.FromAhsv((int)byte.MaxValue, hue, saturation, value);
        }
        public static ColorHSV FromAhsv(int alpha, int hue, int saturation, int value)
        {
            ColorHSV.Check256(alpha, "alpha");
            ColorHSV.Check360(hue, "hue");
            ColorHSV.Check256(saturation, "saturation");
            ColorHSV.Check256(value, "value");
            return new ColorHSV(alpha, hue, saturation, value);
        }
        public static bool operator ==(ColorHSV left, ColorHSV right)
        {
            if (left.m_A != right.m_A || left.m_H != right.m_H || left.m_S != right.m_S || left.m_V != right.m_V) return false;
            return true;
        }
        public static bool operator !=(ColorHSV left, ColorHSV right)
        {
            return !(left == right);
        }
        public static implicit operator ColorHSV(Color color)
        {
            return ColorHSV.FromArgb(color);
        }
        public static implicit operator Color(ColorHSV color)
        {
            return color.ToColor();
        }


        private const string m_ArgumentErrorFormat = "错误的参数 {0} 取值 {1} 不在范围 [{2}, {3}] 内";
        private static void Check256(int value, string name)
        {
            if (value >= 0 && value <= (int)byte.MaxValue) return;
            throw new ArgumentException(string.Format(m_ArgumentErrorFormat, (object)name, (object)value, (object)0, (object)(int)byte.MaxValue));
        }
        private static void Check360(int value, string name)
        {
            if (value >= 0 && value <= (int)359) return;
            throw new ArgumentException(string.Format(m_ArgumentErrorFormat, (object)name, (object)value, (object)0, (object)(int)359));
        }


        private ColorHSV(int alpha, int hue, int saturation, int value)
        {
            this.m_A = (ushort)alpha;
            this.m_H = (ushort)hue;
            this.m_S = (ushort)saturation;
            this.m_V = (ushort)value;

            if (this.m_S == 0) this.m_H = 0;
        }

        private readonly ushort m_A;
        private readonly ushort m_H;
        private readonly ushort m_S;
        private readonly ushort m_V;

        /// <summary>
        /// 透明度 [0, 255]
        /// </summary>
        public int A
        {
            get { return this.m_A; }
        }
        /// <summary>
        /// 色相 [0, 360]
        /// </summary>
        public int H
        {
            get { return this.m_H; }
        }
        /// <summary>
        /// 饱和度 [0, 255]
        /// </summary>
        public int S
        {
            get { return this.m_S; }
        }
        /// <summary>
        /// 明度 [0, 255]
        /// </summary>
        public int V
        {
            get { return this.m_V; }
        }

        /// <summary>
        /// 饱和度 [0, 100]
        /// </summary>
        public int S100
        {
            get { return (int)Math.Round(((float)m_S * 100) / 255); }
        }
        /// <summary>
        /// 明度 [0, 100]
        /// </summary>
        public int V100
        {
            get { return (int)Math.Round(((float)m_V * 100) / 255); }
        }

        /// <summary>
        /// 当前颜色是否是 白色
        /// </summary>
        public bool IsWhite
        {
            get { return this.m_S == 0 && this.m_V == 255; }
        }
        /// <summary>
        /// 当前颜色是否是 黑色
        /// </summary>
        public bool IsBlack
        {
            get { return this.m_V == 0; }
        }


        public Color ToColor()
        {
            int a = this.m_A;
            float h = this.m_H, s = this.m_S, v = this.m_V;
            if (s == 0 && v == 255) return Color.FromArgb(a, 255, 255, 255);           //纯白色时, s==0 且 v==255  而  h 参数是无效的(#FFFFFF 的h 可以是任意值)
            if (v == 0) return Color.FromArgb(a, 0, 0, 0);                             //纯黑色时, v==0 且         而  h s 参数是无效的(#000000 的 h s 可以是任意值)


            //以下代码未经过 高压测试, 可能存在BUG
            float r = 0, g = 0, b = 0;
            if (s == 0) { r = g = b = v; }
            else 
            {
                var t = v;
                var x = (255f - s) * v / 255f;
                var w = (t - x) * (h % 60f) / 60f;

                if (h == 360) { h = 0; }

                if (h < 60) { r = t; b = x; g = x + w; } 
                else if (h < 120) { g = t; b = x; r = t - w; } 
                else if (h < 180) { g = t; r = x; b = x + w; }
                else if (h < 240) { b = t; r = x; g = t - w; }
                else if (h < 300) { b = t; g = x; r = x + w; }
                else if (h < 360) { r = t; g = x; b = t - w; } 
                else { r = 0; g = 0; b = 0; } 
            }

            return Color.FromArgb(a, (int)Math.Round(r), (int)Math.Round(g), (int)Math.Round(b));
        }
        public override string ToString()
        {
            var color = ToColor();
            return color + string.Format(" [H={0}, S={1}, V={2}, S100={3}, V100={4}]", this.H, this.S, this.V, this.S100, this.V100);
        }
        public override bool Equals(object obj)
        {
            if (obj is ColorHSV) { return (ColorHSV)obj == this; }
            return false;
        }
        public override int GetHashCode()
        {
            return this.m_A.GetHashCode() ^ this.m_H.GetHashCode() ^ this.m_S.GetHashCode() ^ this.m_V.GetHashCode();
        }
    }


    #endregion

}


